package com.zhx.common.user.service.impl;

import com.zhx.common.common.annotation.RedissonLock;
import com.zhx.common.common.domain.enums.YesOrNoEnum;
import com.zhx.common.common.event.ItemReceiveEvent;
import com.zhx.common.common.service.LockService;
import com.zhx.common.common.util.AssertUtil;
import com.zhx.common.user.dao.UserBackpackDao;
import com.zhx.common.user.domain.entity.UserBackpack;
import com.zhx.common.user.domain.enums.IdempotentEnum;
import com.zhx.common.user.mapper.UserBackpackMapper;
import com.zhx.common.user.service.IUserBackpackService;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.Objects;


@Service
public class UserBackpackServiceImpl implements IUserBackpackService {

    @Resource
    private UserBackpackDao userBackpackDao;

    @Resource
    private LockService lockService;

    @Resource
    @Lazy
    private UserBackpackServiceImpl userBackpackService;

    @Resource
    private ApplicationEventPublisher applicationEventPublisher;


    /**
     * 用户获取一个物品
     * @param uid 用户id
     * @param itemId 物品id
     * @param idempotentEnum 幂等类型
     * @param businessId 幂等唯一标识
     */
    @Override
    public void acquireItem(Long uid, Long itemId, IdempotentEnum idempotentEnum, String businessId) {
        //生成幂等标识符
        String idempotent = getIdempotent(itemId, idempotentEnum, businessId);
        //发放物品
        userBackpackService.doAcquireItem(uid, itemId, idempotent);
    }

    //这里用到分布式锁，根据用户来做资源的隔离，确保你在一个串行的环境下，判断幂等是否重复。
    @RedissonLock(key = "#idempotent",waitTime = 5000)
    public void doAcquireItem(Long uid, Long itemId, String idempotent) {
        //判断幂等标识符是否存在
        UserBackpack userBackpack = userBackpackDao.getByIdempotent(idempotent);
        //如果不为空
        if (Objects.nonNull(userBackpack)) {
            return;
        }

        //发放物品
        UserBackpack build = UserBackpack.builder()
                .uid(uid)
                .itemId(itemId)
                .status(YesOrNoEnum.NO.getStatus())
                .idempotent(idempotent)
                .build();

        userBackpackDao.save(build);

        //用户收到物品的事件
        applicationEventPublisher.publishEvent(new ItemReceiveEvent(this, build));
    }

    /**
     * 生成幂等标识符
     *
     * @param itemId         物品ID
     * @param idempotentEnum 幂等类型
     * @param businessId     业务ID
     * @return 返回生成的幂等标识符
     */
    private String getIdempotent(Long itemId, IdempotentEnum idempotentEnum, String businessId) {
        return String.format("%d_%d_%s", itemId, idempotentEnum.getType(), businessId);
    }
}
